﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FrameWork.Lib;
using System.ComponentModel;

namespace AnimeWatchMax
{
    public class ThreadManager
    {
        public class UpdateRangeArg
        {
            public int FromTitleID { get; set; }
            public int ToTitleID { get; set; }
        }

        public EventManager EventManager { get; private set; }
        public System.Threading.Thread UpdateThread { get; private set; }
        public System.Threading.Thread UpdateRangeThread { get; private set; }
        public DataObjects.Data Data { get; private set; }
        public bool StopUpdateThread { get; set; }
        public bool StopUpdateRangeThread { get; set; }

        public ThreadManager(EventManager pEventManager)
        {
            this.EventManager = pEventManager;
        }

        public void InitData(DataObjects.Data pData)
        {
            if (!this.StopUpdateThread) this.StopUpdateThread = true;
            if (!this.StopUpdateRangeThread) this.StopUpdateRangeThread = true;

            while (this.UpdateThread != null && this.UpdateThread.IsAlive)
            {
                System.Threading.Thread.Sleep(10);
            }

            this.UpdateThread = null;

            while (this.UpdateRangeThread != null && this.UpdateRangeThread.IsAlive)
            {
                System.Threading.Thread.Sleep(10);
            }

            this.UpdateRangeThread = null;

            this.StopUpdateThread = false;
            this.StopUpdateRangeThread = false;
            this.Data = pData;

        }

        public void StartUpdate()
        {
            if (this.UpdateThread == null || (this.UpdateThread != null && !this.UpdateThread.IsAlive))
            {
                this.UpdateThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.Update));
                this.UpdateThread.Start();
            }
        }

        public void StopUpdate()
        {
            this.StopUpdateThread = true;

            while (this.UpdateThread != null && this.UpdateThread.IsAlive)
            {
                System.Threading.Thread.Sleep(10);
            }

            this.StopUpdateThread = false;
            this.UpdateThread = null;
        }

        public void Update()
        {
            this.EventManager.CheckedAddResult(Result.NewWarning("Update Started."));
            try
            {
                var tXml = FrameWork.Lib.Net.Functions.GetSource("http://www.animesuki.com/xml.php?type=releases&sortname=1&cutoff=10000000");

                if (this.StopUpdateThread) { this.StopUpdateThread = false; return; }

                ProcessAnimeSukiXml(tXml, false);
                 
            }
            catch (Exception exc)
            {
                this.EventManager.CheckedAddResult(new FrameWork.Lib.Result(exc));
            }

            this.EventManager.CheckedAddResult(Result.NewWarning("Update Completed."));

        }

        public void StartUpdateRange(int pFromID, int pToID)
        {
            if (this.UpdateRangeThread == null || (this.UpdateRangeThread != null && !this.UpdateRangeThread.IsAlive))
            {
                this.UpdateRangeThread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(this.UpdateRange));
                this.UpdateRangeThread.Start((object)(new UpdateRangeArg() { FromTitleID = pFromID, ToTitleID = pToID }));
            }
        }

        public void StopUpdateRange()
        {
            this.StopUpdateRangeThread = true;

            while (this.UpdateRangeThread != null && this.UpdateRangeThread.IsAlive)
            {
                System.Threading.Thread.Sleep(10);
            }

            this.StopUpdateRangeThread = false;
            this.UpdateRangeThread = null;
        }

        public void UpdateRange(object arg)
        {
            var tUpdateRangeArg = (UpdateRangeArg)arg;
            UpdateRange(tUpdateRangeArg.FromTitleID, tUpdateRangeArg.ToTitleID);
        }

        public void UpdateRange(int pFromID, int pToID)
        {
            this.EventManager.CheckedAddResult(Result.NewWarning("Update Range Started."));

            var tRangeCount = (pToID - pFromID) + 1;
            var tRangeUpdateProgressGUID = Guid.NewGuid();
            var tRangeCurrentCount = 0;

            for (int i = pFromID; i <= pToID; i++)
            {
                tRangeCurrentCount++;
                this.EventManager.UpdateProgress(tRangeUpdateProgressGUID, tRangeCount, tRangeCurrentCount, string.Format("Current Range {0} out of {1}", tRangeCurrentCount, tRangeCount));

                try
                {
                    if (this.StopUpdateRangeThread)
                    {
                        this.EventManager.UpdateProgress(tRangeUpdateProgressGUID, 0, 0, null);
                        this.StopUpdateRangeThread = false;
                        return;
                    }

                    if (this.Data.IgnoreTitleIDList.Contains(i.ToString())) continue;

                    var tXml = FrameWork.Lib.Net.Functions.GetSource(string.Format("http://www.animesuki.com/xml.php?type=series&id={0}", i));

                    if (tXml.IndexOf("<b>Error:</b>") != -1)
                    {
                        if (tXml.IndexOf("licensed") != -1)
                        {
                            this.Data.IgnoreTitleIDList.Add(i.ToString());
                            this.EventManager.CheckedAddResult(Result.NewError(tXml.Replace("<b>", "").Replace("</b>", "") + " **IGNORED** "));
                        }
                        else
                        {
                            this.EventManager.CheckedAddResult(Result.NewError(tXml.Replace("<b>", "").Replace("</b>", "")));
                        }
                    }
                    else
                    {
                        ProcessAnimeSukiXml(tXml, true);
                    }
                }
                catch (Exception exc)
                {
                    this.EventManager.CheckedAddResult(new FrameWork.Lib.Result(exc));
                }
            }

            this.EventManager.CheckedAddResult(Result.NewWarning("Update Range Completed."));
        }

        private void ProcessAnimeSukiXml(string pXml, bool pRanged)
        {
            var tAnimeSukiData = AnimeWatchMax.XSD.AnimeSukiHandler.GetAnimeSukiDataSetFromXml(pXml);

            if (pRanged && this.StopUpdateRangeThread) { this.StopUpdateRangeThread = false; return; }
            if (!pRanged && this.StopUpdateThread) { this.StopUpdateThread = false; return; }

            var tReleaseCount = tAnimeSukiData.release.Rows.Count;
            var tReleaseUpdateProgressGUID = Guid.NewGuid();
            var tReleaseCurrentCount = 0;

            foreach (AnimeWatchMax.XSD.AnimeSukiDataSet.releaseRow tReleaseRow in tAnimeSukiData.release.Rows)
            {
                tReleaseCurrentCount++;
                this.EventManager.UpdateProgress(tReleaseUpdateProgressGUID, tReleaseCount, tReleaseCurrentCount, "Title Progress...");

                if (pRanged && this.StopUpdateRangeThread)
                {
                    this.EventManager.UpdateProgress(tReleaseUpdateProgressGUID, 0, 0, null);
                    this.StopUpdateRangeThread = false;
                    return;
                }
                else if (!pRanged && this.StopUpdateThread)
                {
                    this.EventManager.UpdateProgress(tReleaseUpdateProgressGUID, 0, 0, null);
                    this.StopUpdateThread = false;
                    return;
                }
                //this.EventManager.UpdateProgress 
                var tEpisodeRows = tReleaseRow.GetepisodeRows();
                var tGroupRows = tReleaseRow.GetgroupRows();
                var tTorrentRows = tReleaseRow.GettorrentRows();
                var tVersionRows = tReleaseRow.GetversionRows();
                var tFileRows = tReleaseRow.GetfileRows();

                var titleid = tReleaseRow.titleid.IntValueOrNull();
                var release_Id = tReleaseRow.release_Id;
                var filesize = tReleaseRow.filesize;
                var filename = tReleaseRow.filename;
                var batch = tReleaseRow.batch;
                var animesuki_Id = tReleaseRow.animesuki_Id;

                if (titleid == null) continue;

                var tTitle = this.Data.TitleList.Where(t => t.ID == titleid.Value).FirstOrDefault();

                if (tTitle == null)
                {
                    tTitle = new DataObjects.Title(titleid.Value)
                    {
                        Description = tReleaseRow.description.StringValueOrEmpty(),
                        Name = tReleaseRow.title.StringValueOrEmpty(),
                        TitleCreatedDate = tReleaseRow.added.UNIXDateValueOrNull(),
                        Status = tReleaseRow.status.ToTitleStatus(),
                        State = TitleStateType.New,
                        ReleasedDate = tReleaseRow.released.UNIXDateValueOrNull()
                    };

                    this.Data.TitleList.Add(tTitle);
                    this.EventManager.CheckedAddResult(Result.NewWarning("New Title Added {0}", tTitle.Name));
                    this.EventManager.AddTitleItem(tTitle);

                }
                else
                {
                    tTitle.Updated = DateTime.Now;
                    tTitle.Description = tReleaseRow.description.StringValueOrEmpty();
                    tTitle.Name = tReleaseRow.title.StringValueOrEmpty();
                    tTitle.TitleCreatedDate = tReleaseRow.added.UNIXDateValueOrNull();
                    tTitle.Status = tReleaseRow.status.ToTitleStatus();
                    tTitle.ReleasedDate = tReleaseRow.released.UNIXDateValueOrNull();
                    this.EventManager.CheckedAddResult(Result.NewWarning("Updated Title {0}", tTitle.Name));
                    this.EventManager.AddTitleItem(tTitle);
                }

                var tEpisodeRow = tEpisodeRows.FirstOrDefault();

                if (tEpisodeRow != null)
                {
                    var tEpisode = tTitle.EpisodeList.Where(t => t.EpisodeText == tEpisodeRow.episode_Text).FirstOrDefault();

                    if (tEpisode != null)
                    {
                        tEpisode.Updated = DateTime.Now;

                    }
                    else
                    {
                        tEpisode = new DataObjects.Episode(tEpisodeRow.order, tEpisodeRow.episode_Text);
                        tTitle.EpisodeList.Add(tEpisode);
                        this.EventManager.CheckedAddResult(Result.NewWarning("New Episode {0} Added For Title {1}", tEpisode.EpisodeText, tTitle.Name));
                    }

                    var tFile = tEpisode.FileList.Where(t => t.Name == filename).FirstOrDefault();

                    if (tFile != null)
                    {
                        tFile.Updated = DateTime.Now;
                    }
                    else
                    {
                        tFile = new DataObjects.File(filename);
                        tEpisode.FileList.Add(tFile);
                    }

                    foreach (var tGroupRow in tGroupRows)
                    {
                        if (this.StopUpdateRangeThread) { this.StopUpdateRangeThread = false; return; }

                        if (!tFile.GroupIDList.Contains(tGroupRow.id))
                        {
                            tFile.GroupIDList.Add(tGroupRow.id);
                        }

                        if (!this.Data.GroupList.Exists(t => t.ID == tGroupRow.id))
                        {
                            this.Data.GroupList.Add(new DataObjects.Group(tGroupRow.id) { ShortName = tGroupRow.abbreviation, LongName = tGroupRow.name });
                        }
                    }

                    var tFileNameList = tFile.FileNameList.Select(t => t.FileName).ToList();
                    foreach (var tFileRow in tFileRows)
                    {
                        if (!tFileNameList.Contains(tFileRow.name))
                        {
                            tFile.FileNameList.Add(new DataObjects.FileNameSize() { FileName = tFileRow.name, Size = tFileRow.size.LongValueOrZero() });
                        }
                    }


                    foreach (var tTorrentRow in tTorrentRows)
                    {


                        if (pRanged && this.StopUpdateRangeThread) { this.StopUpdateRangeThread = false; return; }
                        if (!pRanged && this.StopUpdateThread) { this.StopUpdateThread = false; return; }

                        var tTorrent = tFile.TorrentList.Where(t => t.ID == tTorrentRow.id).FirstOrDefault();

                        if (tTorrent != null)
                        {
                            tTorrent.Updated = DateTime.Now;
                        }
                        else
                        {
                            tTorrent = new DataObjects.Torrent(tTorrentRow.id);
                            tFile.TorrentList.Add(tTorrent);
                        }

                        tTorrent.UL = tTorrentRow.ul.IntValueOrZero();
                        tTorrent.DL = tTorrentRow.dl.IntValueOrZero();
                        tTorrent.Downloaded = tTorrentRow.downloaded.IntValueOrZero();
                        tTorrent.Direct = tTorrentRow.direct;
                        var tSite = tTorrentRow.GetsiteRows().FirstOrDefault();
                        if (tSite != null)
                        {
                            tTorrent.Site = tSite.site_Text;
                            tTorrent.SiteHotLink = tSite.hotlink.BoolValue();
                        }
                        else
                        {
                            tTorrent.Site = "";
                            tTorrent.SiteHotLink = false;
                        }
                        tTorrent.TrackerProblem = tTorrentRow.trackerproblem.BoolValue();
                        tTorrent.Status = tTorrentRow.status.StringValueOrEmpty().ToTorrentStatus();
                    }
                }
            }
        }
    }
}
